package com.h2.ref.server.web.user.openid;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.openid.OpenIDAuthenticationToken;
import org.springframework.security.openid.OpenIDConsumerException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;

import com.h2.ref.server.user.UserService;
import com.h2.ref.server.user.openid.OpenId;
import com.h2.ref.server.user.openid.UserServiceOpenId;
import com.h2.ref.server.web.ViewConstants;
import com.h2.ref.server.web.user.UserFormData;

@Controller
@SessionAttributes(value={"openId", "openid_identifier"})
public class OpenIdUserRegistration {
   
   private static final Logger LOG = LoggerFactory.getLogger(
         OpenIdUserRegistration.class);
   
   ////
   
   private UserService _userService;
   
   private UserServiceOpenId _openIdService;
   
   private OpenIdProvider _openIdProvider;
   
   ////
   ////
   
   @ModelAttribute("user" )
   public UserFormData userModel() {
      return new UserFormData();
   }
   
   @ModelAttribute("openId")
   public OpenId openIdModel() {
      return new OpenId();
   }
   
   @ModelAttribute("openid_identifier")
   public String indentifierModel(HttpServletRequest request) {
      String claimedIdentity = getOpenIdProvider().obtainUsername(request);
      return (claimedIdentity == null) ? "" : claimedIdentity;
   }
  
   @RequestMapping(
         value = ViewConstants.REGISTER_USER_OPENID,
         method = RequestMethod.GET)
   public String setupForm(Model model,
         @ModelAttribute("openid_identifier")
         String identifier,
         @ModelAttribute("openId")
         OpenId openId,
         BindingResult result,
         HttpServletRequest request) {
      
      String identity = request.getParameter("openid.identity");
      
      if (!StringUtils.hasText(identity)) {
//         String claimedIdentity = getOpenIdProvider().obtainUsername(request);
//         if (!StringUtils.hasText(claimedIdentity)) {
//            return "openid.registration";
//         }
//         model.addAttribute("openid_identifier", claimedIdentity);
         
         try {
            String redirectUrl = getOpenIdProvider().obtainIdentity(
                  request, identifier,
                  getOpenIdProvider().buildReturnToUrl(request));
            return ViewConstants.REDIRECT + redirectUrl;
         } catch (OpenIDConsumerException exp) {
            LOG.error("Unable to process claimed identity '"
                  + identifier + "'");
         }
      }
      else {
         OpenIDAuthenticationToken token;
         try {
            token = getOpenIdProvider().readIdentity(request);
         } catch (OpenIDConsumerException exp) {
            throw new AuthenticationServiceException("Consumer error", exp);
         }
         
         openId.setUid(token.getIdentityUrl());
//         return UrlConstants.REDIRECT + UrlConstants.REGISTER_USER_OPENID;
      }
      
      return "openid.registration";
   }
   
   @RequestMapping(
         value = ViewConstants.REGISTER_USER_OPENID,
         method = RequestMethod.POST)
   public String processSubmit(Model model,
            @ModelAttribute("user")
            UserFormData user,
            @ModelAttribute("openId")
            OpenId openId,
            @ModelAttribute("openid_identifier")
            String identifier,
            BindingResult result) {
      
      if (result.hasErrors()) {
         return "openid.registration";
      }
      else if(getUserService().findByUserName(user.getName()) != null) {
         result.rejectValue("user.name", "register.user.invalid");
         return "openid.registration";
      }
      else if (openId.getUid() == null) {
         result.reject("blabla");
      }
      else if(!"xcom rocks".equals(user.getVerificationCode())) {
         result.rejectValue("verificationCode",
               "register.verificationCode.invalid");
      }
      try {
         if (getOpenIdService().loadUserByUsername(openId.getUid()) != null) {
            //openId exists already
            result.reject("blabla");
         }
      } catch (UsernameNotFoundException exp) {
         
      }
      
      if (result.hasErrors()) {
         return "openid.registration";
      }
      
      //add user
      Integer userId = getUserService().addRegisteredUser(
            user.copy(), true).getId();
      
      //add openId
      openId.setUserId(userId);
      getOpenIdService().addOpenId(openId);
      
      
      return ViewConstants.REDIRECT + "/j_spring_openid_security_check";
   }

   /**
    * @return the userService
    */
   public UserService getUserService() {
      return _userService;
   }

   /**
    * @param userService the userService to set
    */
   public void setUserService(UserService userService) {
      _userService = userService;
   }

   /**
    * @return the openIdProvider
    */
   public OpenIdProvider getOpenIdProvider() {
      return _openIdProvider;
   }

   /**
    * @param openIdProvider the openIdProvider to set
    */
   public void setOpenIdProvider(OpenIdProvider openIdProvider) {
      _openIdProvider = openIdProvider;
   }

   /**
    * @return the openIdService
    */
   public UserServiceOpenId getOpenIdService() {
      return _openIdService;
   }

   /**
    * @param openIdService the openIdService to set
    */
   public void setOpenIdService(UserServiceOpenId openIdService) {
      _openIdService = openIdService;
   }

}
